package com.region.spring;

import com.region.common.adapter.logging.LoggerAdapter;
import com.region.common.adapter.logging.LoggerAdapterFactory;
import com.region.common.utils.ClassUtils;
import com.region.core.env.Operators;
import com.region.core.env.PropertiesOperator;
import com.region.core.env.listener.PropertyRefreshListener;
import com.region.http.client.config.ClientConfig;
import com.region.http.client.config.CustomClientConfigurer;
import com.region.http.client.core.RegionClientFactory;
import com.region.http.client.core.RegionClientFactory.RegionClientFactoryBuilder;
import com.region.http.client.protector.RequestProtector;
import com.region.http.client.request.HttpExecutor;
import com.region.http.client.resolver.parameter.ParameterResolver;
import com.region.http.client.resolver.result.ResultResolver;
import com.region.plugin.Interceptor;
import com.region.spring.operator.RegionSpringPropertiesOperator;
import com.region.spring.resolver.MultipartFileParameterResolver;
import com.region.spring.resolver.MultipartFileResultResolver;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;

import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author 26225
 * @date 2024/7/20 15:40
 * @description
 */
public class RegionClientFactoryBean implements InitializingBean, DisposableBean, EnvironmentAware {

    private final LoggerAdapter loggerAdapter = LoggerAdapterFactory.getLogger(getClass());

    private final ClientConfig config;

    private RegionClientFactoryBuilder regionClientFactoryBuilder = RegionClientFactory.builder();

    private RegionClientFactory regionClientFactory;

    private ThreadPoolExecutor poolExecutor;

    private List<CustomClientConfigurer> customClientConfigurers;

    private List<Interceptor> interceptors;

    private List<PropertyRefreshListener> refreshListeners;

    private List<HttpExecutor> httpExecutors;

    private List<RequestProtector> requestProtectors;

    private List<ParameterResolver> parameterResolvers;

    private List<ResultResolver> resultResolvers;

    public RegionClientFactoryBean(ClientConfig config) {
        this.config = config;
    }

    public void setPoolExecutor(ThreadPoolExecutor poolExecutor) {
        this.poolExecutor = poolExecutor;
    }

    public void setCustomClientConfigurers(List<CustomClientConfigurer> customClientConfigurers) {
        this.customClientConfigurers = customClientConfigurers;
    }

    public void setInterceptors(List<Interceptor> interceptors) {
        this.interceptors = interceptors;
    }

    public void setRefreshListeners(List<PropertyRefreshListener> refreshListeners) {
        this.refreshListeners = refreshListeners;
    }

    public void setHttpExecutors(List<HttpExecutor> httpExecutors) {
        this.httpExecutors = httpExecutors;
    }

    public void setRequestProtectors(List<RequestProtector> requestProtectors) {
        this.requestProtectors = requestProtectors;
    }

    public void setParameterResolvers(List<ParameterResolver> parameterResolvers) {
        this.parameterResolvers = parameterResolvers;
    }

    public void setResultResolvers(List<ResultResolver> resultResolvers) {
        this.resultResolvers = resultResolvers;
    }

    public RegionClientFactory getFactory() {
        return regionClientFactory;
    }

    @Override
    public void setEnvironment(Environment environment) {
        PropertiesOperator operator = Operators.createOperator(RegionSpringPropertiesOperator.class);
        if (operator instanceof RegionSpringPropertiesOperator) {
            RegionSpringPropertiesOperator regionSpringPropertiesOperator = (RegionSpringPropertiesOperator) operator;
            regionSpringPropertiesOperator.setEnvironment(environment);
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        regionClientFactoryBuilder.config(this.config);
        if (poolExecutor != null) {
            regionClientFactoryBuilder.asynchronousThreadPoolExecutor(poolExecutor);
        }
        if (httpExecutors != null && !httpExecutors.isEmpty()) {
            httpExecutors.forEach(executor -> regionClientFactoryBuilder.registerExecutor(executor));
        }
        if (requestProtectors != null && !requestProtectors.isEmpty()) {
            requestProtectors.forEach(protector -> regionClientFactoryBuilder.registerProtector(protector));
        }
        if (customClientConfigurers != null && !customClientConfigurers.isEmpty()) {
            customClientConfigurers.forEach(configurer -> regionClientFactoryBuilder.customConfigurer(configurer));
        }
        if (interceptors != null && !interceptors.isEmpty()) {
            interceptors.forEach(interceptor -> regionClientFactoryBuilder.interceptor(interceptor));
        }
        if (refreshListeners != null && !refreshListeners.isEmpty()) {
            refreshListeners.forEach(listener -> regionClientFactoryBuilder.listener(listener));
        }
        if (parameterResolvers != null && !parameterResolvers.isEmpty()) {
            parameterResolvers.forEach(resolver -> regionClientFactoryBuilder.parameterResolver(resolver));
        }
        if (resultResolvers != null && !resultResolvers.isEmpty()) {
            resultResolvers.forEach(resolver -> regionClientFactoryBuilder.resultResolver(resolver));
        }
        try {
            ClassUtils.getClassLoader().loadClass("org.springframework.web.multipart.MultipartFile");
            regionClientFactoryBuilder.parameterResolver(new MultipartFileParameterResolver());
            regionClientFactoryBuilder.resultResolver(new MultipartFileResultResolver());
        } catch (ClassNotFoundException e) {
            loggerAdapter.warn("The default classLoader not found class 'org.springframework.web.multipart.MultipartFile'.");
        }
        regionClientFactory = regionClientFactoryBuilder.build();
    }

    @Override
    public void destroy() throws Exception {
        if (regionClientFactory != null) {
            regionClientFactory.close();
        }
    }
}
